﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace UnsafeCode
{
    class VirtualMemoryManager
    {
        [DllImport("kernel32.dll")]
        internal static extern IntPtr GetCurrentProcess();

        [DllImport("kernel32.dll",SetLastError = true)]
        private static extern IntPtr VirtualAllocEx(
            IntPtr hProcess,
            IntPtr lpAddress,
            IntPtr dwSize,
            AllocationType flAllocationType,
            uint flProtect
            );
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool VirtualProtectEx(
            IntPtr hProcess, 
            IntPtr lpAddress,
            IntPtr dwSize, 
            uint flNewProtect, 
            ref uint lpflOldProtect
            );

        [Flags]
        private enum AllocationType : uint  { Commit = 0x1000, Reserve = 0x2000, Reset = 0x80000, Physical = 0x400000, TopDown = 0x100000, }
        [Flags]
        private enum ProtectionOptions { Execute = 0x10,PageExecuteRead=0x20,  pageExecuteReadWrite =0x40, }
        [Flags]
        private enum MemoryFreeType {Decommit=0x4000, Release=0x8000, }

        public static IntPtr AllocExecutionBlock(int size, IntPtr hProcess)
        {
            IntPtr codeBytesPtr;
            codeBytesPtr = VirtualAllocEx(
                    hProcess, IntPtr.Zero, (IntPtr)size, AllocationType.Reserve | AllocationType.Commit, (uint)ProtectionOptions.pageExecuteReadWrite
                );
            if (codeBytesPtr == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();

            /////////////////////////////////////////////////////////////////////////////////////////////

            uint lpfOldProtect = 0;
            if(!VirtualProtectEx(
                hProcess,codeBytesPtr,
                (IntPtr)size,
                (uint)ProtectionOptions.pageExecuteReadWrite,
                ref lpfOldProtect
                ))  throw new System.ComponentModel.Win32Exception();

            return codeBytesPtr;
        }

        public static IntPtr AllocExecutionBlock(int size)
        {
            return AllocExecutionBlock(size, GetCurrentProcess());
        }
    }
}
